"""
配置验证器
提供配置项值的验证功能，包括数据类型、格式、范围等验证
"""

import re
import json
import logging
from typing import Dict, Optional, Any
from data_models.Config import ValidationResult, DataType


class ConfigValidator:
    """配置验证器"""

    def __init__(self, db_manager):
        self.db_manager = db_manager
        self.logger = logging.getLogger(__name__)

        # 内置验证规则
        self.validation_rules = {
            'port': r'^[0-9]{1,5}$',
            'path': r'^[^\s]+$',
            'email': r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
            'url': r'^https?://[^\s/$.?#].[^\s]*$',
            'api_key': r'^[a-zA-Z0-9_-]+$',
            'timeout': r'^[0-9]+$',
            'boolean': r'^(true|false|1|0|yes|no|on|off)$',
            'json': r'^\{.*\}$|^\[.*\]$',
            'float': r'^-?\d*\.?\d+$',
            'integer': r'^-?\d+$',
            'host': r'^[a-zA-Z0-9.-]+$',
            'filename': r'^[^\\/:*?"<>|]+$'
        }

    async def validate_config_value(self, config_key: str, value: str,
                                   config_metadata: Optional[Dict] = None) -> ValidationResult:
        """
        验证配置值

        Args:
            config_key: 配置键名
            value: 配置值
            config_metadata: 配置元数据（可选，如果不提供会从数据库查询）

        Returns:
            ValidationResult: 验证结果
        """
        try:
            # 如果没有提供元数据，从数据库获取
            if not config_metadata:
                config_metadata = await self._get_config_metadata(config_key)
                if not config_metadata:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"Unknown configuration key: {config_key}"
                    )

            data_type = config_metadata['data_type']
            display_name = config_metadata.get('display_name', config_key)

            # 1. 基础数据类型验证
            type_validation = self._validate_data_type(value, data_type, display_name)
            if not type_validation.is_valid:
                return type_validation

            # 2. 自定义验证规则
            validation_rule = config_metadata.get('validation_rule')
            if validation_rule:
                rule_validation = self._validate_custom_rule(
                    value, validation_rule, display_name
                )
                if not rule_validation.is_valid:
                    return rule_validation

            # 3. 取值范围验证
            value_range = config_metadata.get('value_range')
            if value_range:
                range_validation = self._validate_value_range(
                    value, value_range, data_type, display_name
                )
                if not range_validation.is_valid:
                    return range_validation

            # 4. 特殊配置项验证
            special_validation = self._validate_special_cases(config_key, value, display_name)
            if not special_validation.is_valid:
                return special_validation

            # 5. 依赖关系验证
            dependency_validation = await self._validate_dependencies(config_key, value)
            if not dependency_validation.is_valid:
                return dependency_validation

            # 返回标准化值
            normalized_value = type_validation.normalized_value or value
            return ValidationResult(
                is_valid=True,
                normalized_value=normalized_value
            )

        except Exception as e:
            self.logger.error(f"Validation error for {config_key}: {e}")
            return ValidationResult(
                is_valid=False,
                error_message=f"Validation error: {str(e)}"
            )

    async def validate_config_batch(self, updates: Dict[str, str]) -> Dict[str, ValidationResult]:
        """
        批量验证配置值

        Args:
            updates: 配置更新字典 {key: value}

        Returns:
            Dict[str, ValidationResult]: 验证结果字典
        """
        results = {}

        # 先获取所有配置的元数据
        keys = list(updates.keys())
        metadata_map = {}

        for key in keys:
            metadata = await self._get_config_metadata(key)
            if metadata:
                metadata_map[key] = metadata

        # 验证每个配置项
        for key, value in updates.items():
            metadata = metadata_map.get(key)
            results[key] = await self.validate_config_value(key, value, metadata)

        return results

    async def _get_config_metadata(self, config_key: str) -> Optional[Dict]:
        """获取配置项元数据"""
        try:
            query = """
                SELECT data_type, value_range, validation_rule, is_sensitive,
                       is_reload_required, category, group_id, display_name
                FROM config_items
                WHERE key_name = %s
            """
            result = await self.db_manager.execute_query_one(query, (config_key,))
            return result
        except Exception as e:
            self.logger.error(f"Failed to get config metadata for {config_key}: {e}")
            return None

    def _validate_data_type(self, value: str, data_type: str, display_name: str) -> ValidationResult:
        """验证数据类型"""
        try:
            if data_type == DataType.BOOLEAN.value:
                if value.lower() in ('true', '1', 'yes', 'on'):
                    return ValidationResult(
                        is_valid=True,
                        normalized_value='true'
                    )
                elif value.lower() in ('false', '0', 'no', 'off'):
                    return ValidationResult(
                        is_valid=True,
                        normalized_value='false'
                    )
                else:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be a boolean value (true/false, yes/no, 1/0, on/off)"
                    )

            elif data_type == DataType.INTEGER.value:
                if not self.validation_rules['integer'].match(value):
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be a valid integer"
                    )
                try:
                    int_val = int(value)
                    if int_val < 0:
                        return ValidationResult(
                            is_valid=False,
                            error_message=f"{display_name} must be a non-negative integer"
                        )
                    return ValidationResult(
                        is_valid=True,
                        normalized_value=value
                    )
                except ValueError:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be a valid integer"
                    )

            elif data_type == DataType.FLOAT.value:
                if not self.validation_rules['float'].match(value):
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be a valid number"
                    )
                try:
                    float_val = float(value)
                    return ValidationResult(
                        is_valid=True,
                        normalized_value=value
                    )
                except ValueError:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be a valid number"
                    )

            elif data_type == DataType.PATH.value:
                if not value or not value.strip():
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} cannot be empty"
                    )

                # 检查路径格式
                stripped_value = value.strip()
                if not self.validation_rules['path'].match(stripped_value):
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} contains invalid characters"
                    )

                return ValidationResult(
                    is_valid=True,
                    normalized_value=stripped_value
                )

            elif data_type == DataType.SECRET.value:
                if len(value) < 4:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be at least 4 characters long"
                    )
                return ValidationResult(
                    is_valid=True,
                    normalized_value=value
                )

            elif data_type == DataType.JSON.value:
                try:
                    # 尝试解析JSON
                    json.loads(value)
                    return ValidationResult(
                        is_valid=True,
                        normalized_value=value
                    )
                except json.JSONDecodeError as e:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be valid JSON format: {str(e)}"
                    )

            else:  # STRING
                if len(value) > 1000:  # 限制字符串长度
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} is too long (max 1000 characters)"
                    )
                return ValidationResult(
                    is_valid=True,
                    normalized_value=value.strip() if value.strip() else value
                )

        except Exception as e:
            return ValidationResult(
                is_valid=False,
                error_message=f"Type validation error for {display_name}: {str(e)}"
            )

    def _validate_custom_rule(self, value: str, rule: str, display_name: str) -> ValidationResult:
        """验证自定义规则"""
        try:
            pattern = re.compile(rule)
            if pattern.match(value):
                return ValidationResult(is_valid=True)
            else:
                return ValidationResult(
                    is_valid=False,
                    error_message=f"{display_name} does not match required format"
                )
        except re.error as e:
            self.logger.error(f"Invalid validation rule: {rule} - {e}")
            return ValidationResult(
                is_valid=False,
                error_message=f"Validation rule configuration error"
            )

    def _validate_value_range(self, value: str, value_range: str, data_type: str, display_name: str) -> ValidationResult:
        """验证取值范围"""
        try:
            range_config = json.loads(value_range)

            if isinstance(range_config, list):
                # 枚举值验证
                if value not in range_config:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be one of: {', '.join(map(str, range_config))}"
                    )

            elif isinstance(range_config, dict):
                # 范围验证
                min_val = range_config.get('min')
                max_val = range_config.get('max')

                if data_type in [DataType.INTEGER.value, DataType.FLOAT.value]:
                    try:
                        num_val = float(value)
                        if min_val is not None and num_val < min_val:
                            return ValidationResult(
                                is_valid=False,
                                error_message=f"{display_name} must be >= {min_val}"
                            )
                        if max_val is not None and num_val > max_val:
                            return ValidationResult(
                                is_valid=False,
                                error_message=f"{display_name} must be <= {max_val}"
                            )
                    except ValueError:
                        return ValidationResult(
                            is_valid=False,
                            error_message=f"{display_name} must be a valid number"
                        )
                else:
                    # 字符串长度范围
                    str_len = len(value)
                    if min_val is not None and str_len < min_val:
                        return ValidationResult(
                            is_valid=False,
                            error_message=f"{display_name} must be at least {min_val} characters"
                        )
                    if max_val is not None and str_len > max_val:
                        return ValidationResult(
                            is_valid=False,
                            error_message=f"{display_name} must be at most {max_val} characters"
                        )

            return ValidationResult(is_valid=True)

        except json.JSONDecodeError:
            return ValidationResult(
                is_valid=False,
                error_message=f"Invalid value range configuration for {display_name}"
            )

    def _validate_special_cases(self, key: str, value: str, display_name: str) -> ValidationResult:
        """特殊配置项验证"""
        # 端口范围验证
        if 'port' in key.lower():
            try:
                port = int(value)
                if not (1 <= port <= 65535):
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be between 1 and 65535"
                    )
            except ValueError:
                return ValidationResult(
                    is_valid=False,
                    error_message=f"{display_name} must be a valid port number"
                )

        # 超时时间验证
        elif 'timeout' in key.lower():
            try:
                timeout = int(value)
                if timeout < 0 or timeout > 3600:  # 最大1小时
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be between 0 and 3600 seconds"
                    )
            except ValueError:
                return ValidationResult(
                    is_valid=False,
                    error_message=f"{display_name} must be a valid timeout value"
                )

        # 连接池大小验证
        elif 'pool_size' in key.lower():
            try:
                pool_size = int(value)
                if pool_size < 1 or pool_size > 100:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be between 1 and 100"
                    )
            except ValueError:
                return ValidationResult(
                    is_valid=False,
                    error_message=f"{display_name} must be a valid pool size"
                )

        # 重试次数验证
        elif 'retry' in key.lower() and ('count' in key.lower() or 'attempt' in key.lower()):
            try:
                retry_count = int(value)
                if retry_count < 0 or retry_count > 10:
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be between 0 and 10"
                    )
            except ValueError:
                return ValidationResult(
                    is_valid=False,
                    error_message=f"{display_name} must be a valid retry count"
                )

        # 主机地址验证
        elif 'host' in key.lower() or 'server' in key.lower():
            if value.lower() not in ['localhost', '0.0.0.0', '127.0.0.1']:
                # 验证IP地址或域名格式
                if not (self.validation_rules['host'].match(value) or self._is_valid_ip(value)):
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"{display_name} must be a valid hostname or IP address"
                    )

        # 邮箱验证
        elif 'email' in key.lower():
            if not self.validation_rules['email'].match(value):
                return ValidationResult(
                    is_valid=False,
                    error_message=f"{display_name} must be a valid email address"
                )

        # URL验证
        elif 'url' in key.lower():
            if not self.validation_rules['url'].match(value):
                return ValidationResult(
                    is_valid=False,
                    error_message=f"{display_name} must be a valid URL starting with http:// or https://"
                )

        return ValidationResult(is_valid=True)

    def _is_valid_ip(self, ip: str) -> bool:
        """验证IP地址格式"""
        try:
            parts = ip.split('.')
            if len(parts) != 4:
                return False
            for part in parts:
                if not 0 <= int(part) <= 255:
                    return False
            return True
        except:
            return False

    async def _validate_dependencies(self, key: str, value: str) -> ValidationResult:
        """验证配置依赖关系"""
        try:
            # 获取依赖关系
            query = """
                SELECT d.depends_on_key, d.dependency_type, d.dependency_condition,
                       i.current_value, i.key_name
                FROM config_dependencies d
                JOIN config_items i ON d.depends_on_config_id = i.id
                JOIN config_items ci ON d.config_id = ci.id
                WHERE ci.key_name = %s
            """
            dependencies = await self.db_manager.execute_query(query, (key,))

            for dep in dependencies:
                dep_key = dep['depends_on_key']
                dep_type = dep['dependency_type']
                dep_condition = dep['dependency_condition']
                dep_value = dep['current_value']

                if not self._check_dependency_condition(dep_type, dep_condition, dep_value, value):
                    return ValidationResult(
                        is_valid=False,
                        error_message=f"Configuration dependency validation failed: {key} depends on {dep_key}"
                    )

            return ValidationResult(is_valid=True)

        except Exception as e:
            self.logger.error(f"Dependency validation error for {key}: {e}")
            # 依赖验证失败不应该阻止配置更新，只记录警告
            return ValidationResult(is_valid=True)

    def _check_dependency_condition(self, dep_type: str, condition: str,
                                   dep_value: str, current_value: str) -> bool:
        """检查依赖条件"""
        try:
            if dep_type == 'enable':
                # 依赖项必须启用
                if dep_value.lower() not in ('true', '1', 'yes', 'on'):
                    return False

            elif dep_type == 'value':
                # 依赖值必须匹配条件
                if not condition:
                    return True

                condition_dict = json.loads(condition)
                expected_value = condition_dict.get('expected_value')
                if dep_value != expected_value:
                    return False

            elif dep_type == 'range':
                # 依赖值必须在指定范围内
                if not condition:
                    return True

                condition_dict = json.loads(condition)
                min_val = condition_dict.get('min')
                max_val = condition_dict.get('max')

                try:
                    num_val = float(dep_value)
                    if min_val is not None and num_val < min_val:
                        return False
                    if max_val is not None and num_val > max_val:
                        return False
                except ValueError:
                    return False

            return True

        except (json.JSONDecodeError, ValueError, KeyError) as e:
            self.logger.error(f"Error checking dependency condition: {e}")
            return True  # 依赖检查失败时允许更新